<?php
/**
 * helper.func.php
 * @copyright (c) 2011-2020, Hangzhou DOJI Tech Co., Ltd.
 * This is NOT a freeware, use is subject to license terms.
 * @package helper.function.php
 * @link https://www.tingjunapp.com/
 * @author wujun@lanqb.cn
 * @$Id: helper.func.php 310000 2020-11-07 21:13:44 $
 * */

use App\Common\Libs\ArrayHelper;
use App\Consts\ExceptionCode;
use App\Consts\GlobalAPIReturnConst;
use App\Consts\GlobalLoginConst;
use App\Exceptions\Error;
use App\Models\Cache\Cache;
use App\Models\Cache\CacheKey;
use App\Repository\Repository;
use App\Services\Service;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Response;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpKernel\Exception\HttpException;

if (!function_exists('service')) {
    /**
     * get service instance
     * @return \App\Services\Service|array|string|null
     */
    function service()
    {
        static $service = [];
        if ($service instanceof Service) {
            return $service;
        }
        return new Service();
    }
}

if (!function_exists('repository')) {
    /**
     * get repository instance
     * @return \App\Repository\Repository|array|string|null
     */
    function repository()
    {
        static $repository = [];
        if ($repository instanceof Repository) {
            return $repository;
        }
        return new Repository();
    }
}

if (!function_exists('formats')) {
    /**
     * get repository instance
     * @return \App\Repository\Repository|array|string|null
     */
    function formats()
    {
        static $buildFactory = [];
        if ($buildFactory instanceof \App\Formats\Formats) {
            return $buildFactory;
        }
        return new \App\Formats\Formats();
    }
}

if (!function_exists('enableQueryLog')) {
    /**
     * enable query log
     * @return bool
     */
    function enableQueryLog()
    {
        DB::connection()->enableQueryLog();
        return true;
    }
}

if (!function_exists('getQueryLog')) {
    /**
     * get query log
     * @param bool $dump
     * @return mixed
     */
    function getQueryLog($dump = false)
    {
        $logs = DB::connection()->getQueryLog();
        $dump && dd($logs);
        return $logs;
    }
}

if (!function_exists('isLocal')) {
    /**
     * 判断当前环境是否为 local
     * @return bool
     */
    function isLocal()
    {
        return env('APP_ENV') === 'local';
    }
}

if (!function_exists('isDev')) {
    /**
     * 判断当前环境是否为 dev
     * @return bool
     */
    function isDev()
    {
        return env('APP_ENV') === 'dev';
    }
}


if (!function_exists('isTest')) {
    /**
     * 判断当前环境是否为 test
     * @return bool
     */
    function isTest()
    {
        return env('APP_ENV') === 'test';
    }
}


if (!function_exists('isProd')) {
    /**
     * 判断当前环境是否为 prod
     * @return bool
     */
    function isProd()
    {
        return env('APP_ENV') === 'prod';
    }
}


if (!function_exists('isDebug')) {
    /**
     * 判断是否开启 debug
     * @return bool
     */
    function isDebug()
    {
        return env('APP_DEBUG') !== false;
    }
}


if (!function_exists('isAccess')) {
    /**
     * 判断是否开启 access
     * @return bool
     */
    function isAccess()
    {
        return env('API_ACCESS') !== false;
    }
}

if (!function_exists('getRealIp')) {
    /**
     * 获取客户端真实IP
     * @return string|null
     */
    function getRealIp()
    {
        $ip = '';
        $server = $_SERVER;
        if (!empty($server['HTTP_X_FORWARDED_FOR'])) {
            $ips = explode(',', $server['HTTP_X_FORWARDED_FOR']);
            $ip = $ips[0];
        } elseif (!empty($server['REMOTE_ADDR'])) {
            $ip = $server['REMOTE_ADDR'];
        }
        return $ip ?: request()->getClientIp();
    }
}

if (!function_exists('lang')) {
    /**
     * 获取语言包翻译
     * [!] 语言包配置文件 ：resource/lang/*
     * @param $key
     * @return array|\Illuminate\Contracts\Translation\Translator|string|null
     */
    function lang($key)
    {
        if (false !== strpos($key, '.')) {
            if (false === strpos($key, ' ')) {
                return trans($key);
            } else {
                $model = explode('.', $key, 2);
                if (isset($model[1]) && $model[1]) {
                    return trans($model[0] . '.' . $model[1]);
                }
            }
        }
        if (app('translator')->has('default.' . $key)) {
            return trans('default.' . $key);
        }
        return $key;
    }
}

if (!function_exists('corsHeader')) {
    /**
     * 获取 Cors Headers
     * [!] 可参见 config/cors.php 详细配置
     * @return array
     */
    function corsHeader()
    {
        $origin = request()->headers->get('Origin') ?: '';
        $headers = 'X-Requested-With, Authorization, Origin, Content-Type, Cookie, Set-Cookie, X-CSRF-TOKEN, Accept, Authorization, X-XSRF-TOKEN, Token';
        return [
            'Access-Control-Allow-Credentials' => 'true',
            'Access-Control-Allow-Origin' => $origin,
            'Access-Control-Allow-Methods' => 'GET, POST, PATCH, PUT, OPTIONS',
            'Access-Control-Allow-Headers' => $headers,
        ];
    }
}


if (!function_exists('jsonReturn')) {
    /**
     * 接口统一 json 返回
     * [!] 可能接收到的场景：
     *     - Controller    直接返回     （包含错误捕获和成功结果）
     *     - Service       直接返回     （包含错误流程处理和成功结果）
     *     - Error::handle 错误返回     （包含各种错误信息结果）
     *     - HttpClient    请求结果返回 （微服务或第三方请求结果）
     * [!] 可能接收的值域有：
     *     - array        （最常用）
     *     - JsonResponse
     *     - Response
     *     - Collection
     *     - object
     *     - query
     *     - string
     *     - integer
     *     - null
     * [!] 重定向支持，append：
     *     - $data['__REDIRECT_URL'] = 'https://www.baidu.com';
     * [!] Cookie支持，append：
     *     - $data['__COOKIES'] = ['token' => 'XXXX', 'uid' => '00XP'];
     * @param array $data
     * @param int $code
     * @param string $message
     * @return JsonResponse|\Illuminate\Http\RedirectResponse
     */
    function jsonReturn($data = [], $code = 200, $message = '')
    {
        $message = $message ?: lang('Success');
        $code = intval($code);
        $success = $code == 200 ? true : false;
        if (!$success) {
            $message = Error::getMessage($code);
        }
        // 判断是否可以直接返回
        $keys = ['message', 'statusCode', 'success', 'result'];
        if (is_array($data)) {
            if (!empty($data) && empty(array_diff(array_keys($data), $keys))) {
                return response()->json($data);
            } elseif (empty($data)) {
                $data = (object)[];
            }
        } elseif ($data instanceof JsonResponse) {
            $data = $data->getOriginalContent();
            if (!empty($data) && empty(array_diff(array_keys($data), $keys))) {
                return response()->json($data);
            }
        } elseif ($data instanceof Response) {
            $content = $data->getContent();
            $data = json_decode($content, true);
            if (!empty($data) && empty(array_diff(array_keys($data), $keys))) {
                return response()->json($data);
            }
            $data = $content;
        } elseif ($data instanceof Collection) {
            $data = $data->toArray();
        } elseif (is_object($data)) {
            $data = (array)$data ?: (json_decode(json_encode($data), true) ?: json_encode($data));
        } elseif (empty($data)) {
            //$data 绝对等于 false 时，result 返回false
            $data = $data === false ? false : (object)[];
        }

        $format = [
            'success' => $success,
            'statusCode' => $code,
            'message' => $message,
            'result' => $data,
        ];
        // 重定向 和 Cookie 支持
        if (is_array($data) && isset($data[GlobalAPIReturnConst::__REDIRECT_URL])) {
            return redirect()->away($data[GlobalAPIReturnConst::__REDIRECT_URL]);
        } elseif (is_array($data) && isset($data[GlobalAPIReturnConst::__COOKIES])) {
            $cookie = $data[GlobalAPIReturnConst::__COOKIES];
            unset($format['result'][GlobalAPIReturnConst::__COOKIES]);
            if (empty($format['result'])) $format['result'] = (object)[];
            $response = response()->json($format);
            if (is_array($cookie)) {
                foreach ($cookie as $key => $val) {
                    !is_numeric($key) && $response = $response->cookie($key, $val);
                }
            } elseif (is_string($cookie)) {
                $response = $response->cookie(GlobalAPIReturnConst::__DEFAULT_COOKIE_NAME, $cookie);
            }
            return $response;
        }
        return response()->json($format);
    }
}

if (!function_exists('appThrow')) {
    /**
     * app error throw
     * @param \Exception|mixed $exception
     * @param bool $extra
     * @param bool $isSend
     */
    function appThrow($exception, $extra = true, $isSend = true)
    {
        // send sentry log
        if ($isSend) sendSentry($exception);
        $message = $exception->getMessage();
        $extra && $message .= ' @file[ ' . $exception->getFile() . ' : ' . $exception->getLine() . ' ]. ';
        throw new HttpException(ExceptionCode::CODE_FAIL, "[{$exception->getCode()}] - " . $message);
    }
}

if (!function_exists('sendSentry')) {
    /**
     * send exception to sentry
     * @param $exception
     * @return bool
     */
    function sendSentry($exception)
    {
        if (app()->bound('sentry')) {
            return app('sentry')->captureException($exception);
        }
        return false;
    }
}

if (!function_exists('getConfigByKey')) {
    /**
     * 从 config 表中获取指定配置
     * @param $key
     * @return bool
     */
    function getConfigByKey($key)
    {
        return \repository()->ConfigRepository->getConfigByKey($key);
    }
}

if (!function_exists('createTable')) {
    /**
     * 如果表不存在则创建表
     * @param $tableName
     * @param string $oldTable
     * @return bool
     */
    function createTable($tableName, $oldTable = '')
    {
        $tables = DB::select('SHOW TABLES');
        $tables = ArrayHelper::getColumn($tables, 'Tables_in_' . env('DB_DATABASE'));
        if (!in_array($tableName, $tables) && $oldTable) {
            DB::select('CREATE TABLE IF NOT EXISTS `' . $tableName . '` (LIKE `' . $oldTable . '`);');
        }
        return true;
    }
}

if (!function_exists('getSql')) {
    /**
     * 根据 query 获取 sql 语句
     * @param \Illuminate\Database\Eloquent\Builder|string $query
     * @param array $bindings
     * @param bool $die
     * @return mixed|string
     */
    function getSql($query, $bindings = [], $die = false)
    {
        $sql = is_string($query) ? $query : $query->toSql();
        $bindings = $bindings ?: $query->getBindings();
        $sql = str_replace('?', "'%s'", $sql);
        $sql = vsprintf($sql, $bindings);
        if ($die) dd($sql);
        return $sql;
    }
}

if (!function_exists('verifyAccessTokenInCache')) {
    function verifyAccessTokenInCache($accessToken)
    {
        // 如果cookie或header中的token不在缓存中，说明登录态失效
        return Cache::getInstance([
            'platform' => GlobalLoginConst::LOGIN_PLATFORM_WEB_STR,
            'token' => $accessToken,
        ])->judgeValueExist(CacheKey::USER_LOGIN_STATUS);
    }
}
